/**
 * @file keypad.c
 * @brief COSC361 - MCU Jukebox Project\n
 * Group: Hamish Cumming, Brian Thorne\n
 * Latest source can be obtained using SVN from google's code repository with the following command:\n
 * svn checkout http://mega8-hob.googlecode.com/svn/trunk/ jukebox-hamish-brian\n
 * Description: Source file for the keypad module\n
 * Date: 25/5/2008
 */

#include "keypad.h"
#include "Board.h"

static unsigned int previous_state = 0;

/**
 * @brief Scans the keypad for input including debouncing
 * @return An integer bit field representing which buttons are down
 */
unsigned int keypad_scan(void)
{
    static int debounce = 0; //the debounce 'timer'
    static int previous = 0; //which buttons were down last time, for debouncing
    unsigned int input = 0;
    unsigned int output = 0; //How the info is stored, one bit per key (16 bits)
    int i,j;
    /* If we are debouncing, return*/
    if (debounce)
    {
        debounce--;
        return previous;
    }
    /* Set each column low and scan the rows */
    for (i = 0; i < KEYPAD_NUM_COLS; i++){
        AT91F_PIO_SetOutput(AT91C_BASE_PIOA, (KEYPAD_COL1 | KEYPAD_COL2 | KEYPAD_COL3 | KEYPAD_COL4));
        AT91F_PIO_ClearOutput( AT91C_BASE_PIOA, (KEYPAD_COL1 << i));
        input = AT91F_PIO_GetInput(AT91C_BASE_PIOA);
        for (j = 0; j < KEYPAD_NUM_ROWS; j++){
            if ((~input) & (KEYPAD_ROW1 << j)){
                output |= (1 << (KEYPAD_NUM_COLS * i + j));
            }
        }
    }
    /* If a button is down, start debouncing */
    if(output) debounce = 40;
    previous = output;
    return output;
}

/**
 * @brief Initialise the keyboard.
 */
void keypad_init(void)
{
    AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, KEYPAD_COL1 | KEYPAD_COL2 | KEYPAD_COL3 | KEYPAD_COL4);
    AT91F_PIO_SetOutput(AT91C_BASE_PIOA, (KEYPAD_COL1 | KEYPAD_COL2 | KEYPAD_COL3 | KEYPAD_COL4));
    AT91F_PIO_CfgInput(AT91C_BASE_PIOA, KEYPAD_ROW1 | KEYPAD_ROW2 | KEYPAD_ROW3 | KEYPAD_ROW4);
    previous_state = 0;
}

/**
 * @return a word with each bit corresponding each key. True for a just released key.
 */
unsigned int keypad_getKeys(void)
{
    //must save state
    unsigned int result,state = keypad_scan();
    result = (previous_state & ~state);
    previous_state = state;
    return result;
}

/**
 * @brief Determines if a key is down
 * @param key The key to check (as defined in keypad.h)
 * @return true if the key is down
 */
int keypad_keyDowm(unsigned int key)
{
    return key & keypad_scan();
}
